{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "<img src=\"../../img/ods_stickers.jpg\">\n",
    "\n",
    "## <center> [mlcourse.ai](https://mlcourse.ai) – открытый курс OpenDataScience по машинному обучению \n",
    "    \n",
    "Автор материала: Виталий Радченко, Data scientist @ YouScan (@vradchenko в Slack ODS). Материал распространяется на условиях лицензии [Creative Commons CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/). Можно использовать в любых целях (редактировать, поправлять и брать за основу), кроме коммерческих, но с обязательным упоминанием автора материала"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# <center> Домашнее задание № 5 (Демо).\n",
    "## <center> Логистическая регрессия и случайный лес в задаче кредитного скоринга"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[Веб-форма](https://docs.google.com/forms/d/1HASy2b_FLBHBCzzpG-TbnbB6gqhB-qwznQxU2vaoSgc/) для ответов.\n",
    "\n",
    "#### Нашей главной задачей будет построение модели для задачи кредитного скоринга.\n",
    "\n",
    "Но для разминки решите первое задание :)\n",
    "\n",
    "**Задание 1.** В зале суда есть 5 присяжных, каждый из них по отдельности с вероятностью 70% может правильно определить, виновен подсудимый или нет. С какой вероятностью они все вместе вынесут правильный вердикт, если решение принимается большинством голосов?\n",
    "- 70.00%\n",
    "- 83.20%\n",
    "- 83.70%\n",
    "- 87.50%\n",
    "\n",
    "Теперь перейдем непосредственно к машинному обучению.\n",
    "\n",
    "#### Данные представлены следующим образом:\n",
    "\n",
    "##### Прогнозируемая  переменная\n",
    "* SeriousDlqin2yrs\t      – Человек не выплатил данный кредит в течение 90 дней; возможные значения  1/0 \n",
    "\n",
    "##### Независимые признаки\n",
    "* age\t                          –  Возраст заёмщика кредитных средств; тип - integer\n",
    "* NumberOfTime30-59DaysPastDueNotWorse\t – Количество раз, когда человек имел просрочку выплаты других кредитов более 30-59 дней, но не больше в течение последних двух лет; тип -\tinteger\n",
    "* DebtRatio  – \tЕжемесячный отчисления на задолжености(кредиты,алименты и т.д.)  / совокупный месячный доход \tpercentage; тип -\treal\n",
    "* MonthlyIncome\t – Месячный доход в долларах; тип -\treal\n",
    "* NumberOfTimes90DaysLate  – Количество раз, когда человек имел просрочку выплаты других кредитов более 90 дней; тип -\tinteger\n",
    "* NumberOfTime60-89DaysPastDueNotWorse – \tКоличество раз, когда человек имел просрочку выплаты других кредитов более 60-89 дней, но не больше в течение последних двух лет; тип -\tinteger\n",
    "* NumberOfDependents  – Число человек в семье кредитозаёмщика; тип -\tinteger"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "# отключим предупреждения Anaconda\n",
    "import warnings\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "import numpy as np\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## Сделаем функцию, которая будет заменять NaN значения на медиану в каждом столбце таблицы\n",
    "def delete_nan(table):\n",
    "    for col in table.columns:\n",
    "        table[col] = table[col].fillna(table[col].median())\n",
    "    return table"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## Считываем данные\n",
    "data = pd.read_csv(\"../../data/credit_scoring_sample.csv\", sep=\";\")\n",
    "data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## Рассмотрим типы считанных данных\n",
    "data.dtypes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## Посмотрим на распределение классов в зависимой переменной\n",
    "\n",
    "ax = data[\"SeriousDlqin2yrs\"].hist(orientation=\"horizontal\", color=\"red\")\n",
    "ax.set_xlabel(\"number_of_observations\")\n",
    "ax.set_ylabel(\"unique_value\")\n",
    "ax.set_title(\"Target distribution\")\n",
    "\n",
    "print(\"Distribution of target\")\n",
    "data[\"SeriousDlqin2yrs\"].value_counts() / data.shape[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## Выберем названия всех признаков из таблицы, кроме прогнозируемого\n",
    "\n",
    "independent_columns_names = data.columns.values\n",
    "independent_columns_names = [x for x in data if x != \"SeriousDlqin2yrs\"]\n",
    "independent_columns_names"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## Применяем функцию, заменяющую все NaN значения на медианное значение соответствующего столбца\n",
    "table = delete_nan(data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## Разделяем таргет и признаки\n",
    "X = table[independent_columns_names]\n",
    "y = table[\"SeriousDlqin2yrs\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Бутстрэп"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задание 2.** Сделайте интервальную оценку среднего возраста (age) для клиентов, которые просрочили выплату кредита, с 90% \"уверенностью\". Используйте пример из статьи, поставьте `np.random.seed(0)`, как это сделано в статье."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Ваш код должен быть здесь ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Подбор параметров для модели логистической регрессии "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Одной из важных метрик качества модели является значение площади под ROC-кривой. Значение ROC-AUC лежит от 0  до 1.   Чем ближе начение метрики ROC-AUC к 1, тем качественнее происходит классификация моделью."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.linear_model import LogisticRegression\n",
    "from sklearn.model_selection import GridSearchCV, StratifiedKFold\n",
    "\n",
    "## Используем модуль LogisticRegression для построения логистической регрессии.\n",
    "## Из-за несбалансированности классов  в таргете добавляем параметр балансировки.\n",
    "## Используем также параметр random_state=5 для воспроизводимости результатов\n",
    "lr = LogisticRegression(random_state=5, class_weight=\"balanced\")\n",
    "\n",
    "## Попробуем подобрать лучший коэффициент регуляризации (коэффициент C в логистической регрессии) для модели лог.регрессии.\n",
    "## Этот параметр необходим для того, чтобы подобрать оптимальную модель, которая не будет переобучена, с одной стороны,\n",
    "## и будет хорошо предсказывать значения таргета, с другой.\n",
    "## Остальные параметры оставляем по умолчанию.\n",
    "parameters = {\"C\": (0.0001, 0.001, 0.01, 0.1, 1, 10)}\n",
    "\n",
    "## Для того, чтобы подобрать коэффициент регуляризации, попробуем для каждого его возможного значения посмотреть\n",
    "## значения roc-auc на стрэтифайд кросс-валидации из 5 фолдов с помощью функции StratifiedKFold\n",
    "\n",
    "skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задание 3.**\n",
    "Сделайте GridSearch с метрикой \"roc-auc\" по параметру C. Какое оптимальное значение параметра С?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Ваш код должен быть здесь ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задание 4.** \n",
    "Можно ли считать лучшую модель устойчивой? (модель считаем устойчивой, если стандартное отклонение на валидации меньше 0.5%) Сохраните точность лучшей модели, она вам приходится для следующих заданий"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Ваш код должен быть здесь ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Определение влияния признаков"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задание 5.**\n",
    "Определите самый важный признак. Важность признака определяется абсолютным значением его коэффициента. Так же нужно нормализировать все признаки, что бы можно их было корректно сравнить."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Ваш код должен быть здесь ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задание 6.** Посчитайте долю влияния DebtRatio на предсказание. (Воспользуйтесь функцией [softmax](https://en.wikipedia.org/wiki/Softmax_function))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Ваш код должен быть здесь ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задание 7.** \n",
    "Давайте посмотрим как можно интерпретировать влияние наших признаков. Для этого заного оценим логистическую регрессию в абсолютных величинах. После этого посчитайте во сколько раз увеличатся шансы, что клиент не выплатит кредит, если увеличить возраст на 20 лет при всех остальных равных значениях признаков. (теоретический расчет можно посмотреть [здесь](https://www.unm.edu/~schrader/biostat/bio2/Spr06/lec11.pdf))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Ваш код должен быть здесь ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Случайный лес"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.ensemble import RandomForestClassifier\n",
    "\n",
    "# Инициализируем случайный лес с 100 деревьями и сбалансированными классами\n",
    "rf = RandomForestClassifier(\n",
    "    n_estimators=100,\n",
    "    n_jobs=-1,\n",
    "    random_state=42,\n",
    "    oob_score=True,\n",
    "    class_weight=\"balanced\",\n",
    ")\n",
    "\n",
    "## Будем искать лучшие параметры среди следующего набора\n",
    "parameters = {\n",
    "    \"max_features\": [1, 2, 4],\n",
    "    \"min_samples_leaf\": [3, 5, 7, 9],\n",
    "    \"max_depth\": [5, 10, 15],\n",
    "}\n",
    "\n",
    "## Делаем опять же стрэтифайд k-fold валидацию. Инициализация которой должна у вас продолжать храниться в skf"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задание 8.** На сколько точность лучшей модели случайного леса выше точности логистической регрессии на валидации?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Ваш код должен быть здесь ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задание 9.** Определите какой признак имеет самое слабое влияние."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Ваш код должен быть здесь ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** Задание 10.** Какое наиболее существенное примущество логистической регрессии перед случайным лесом для нашей бизнес-задачи?\n",
    "\n",
    "- меньше тратится времени для тренировки модели;\n",
    "- меньше параметров для перебора;\n",
    "- интепретируемость признаков;\n",
    "- линейные свойства алгоритма."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Бэггинг"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.ensemble import BaggingClassifier\n",
    "from sklearn.model_selection import RandomizedSearchCV\n",
    "\n",
    "parameters = {\n",
    "    \"max_features\": [2, 3, 4],\n",
    "    \"max_samples\": [0.5, 0.7, 0.9],\n",
    "    \"base_estimator__C\": [0.0001, 0.001, 0.01, 1, 10, 100],\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задание 11.** Следующая задача обучить бэггинг классификатор (`random_state`=42). В качестве базовых классификаторов возьмите 100 логистических регрессий и на этот раз используйте не `GridSearchCV`, а `RandomizedSearchCV`. Так как перебирать все 54 варианта комбинаций долго, то поставьте максимальное число итераций 20 для `RandomizedSearchCV`. Также не забудьте передать параметр валидации `cv` и `random_state=1`. Какая лучшая точность получилась?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Ваш код должен быть здесь ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задача 12.** Дайте интерпретацию лучших параметров для бэггинга. Почему именно такие значения оказались лучшими?\n",
    "\n",
    "- для бэггинга важно использовать как можно меньше признаков\n",
    "- бэггинг лучше работает на небольших выборках\n",
    "- меньше корреляция между одиночными моделями\n",
    "- чем больше признаков, тем меньше теряется информации"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
